/*
 * Copyright (c) 2020-2099 the original author or authors. All rights reserve.
 */
package org.tianyun.cloud.datasource.hikari;

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.util.Assert;
import org.tianyun.cloud.datasource.WrappedDataSource;
import org.tianyun.cloud.datasource.configuration.HikariProperties;

import javax.sql.DataSource;
import java.util.Properties;

/**
 * HikariDataSourceBuilder
 *
 * @auther ebert_chan
 */
public class HikariDataSourceBuilder {

    private HikariConfig hikariConfig;

    private boolean wrapped;

    private HikariDataSourceBuilder(HikariConfig hikariConfig) {
        this.hikariConfig = hikariConfig;
    }

    public static HikariDataSourceBuilder configure(HikariProperties hikariProperties, Properties props) {
        Assert.hasText(hikariProperties.getDriverClassName(), "Failed to create the datasource, this argument 'driverClassName' is required; it must not be empty");
        Assert.hasText(hikariProperties.getJdbcUrl(), "Failed to create the datasource, this argument 'jdbcUrl' is required; it must not be empty");
        Assert.hasText(hikariProperties.getUsername(), "Failed to create the datasource, this argument 'username' is required; it must not be empty");
        Assert.hasText(hikariProperties.getPassword(), "Failed to create the datasource, this argument 'password' is required; it must not be empty");
        Assert.notNull(hikariProperties.getMaximumPoolSize(), "Failed to create the datasource, this argument 'maximumPoolSize' is required; it must not be null");
        Assert.notNull(hikariProperties.getMinimumIdle(), "Failed to create the datasource, this argument 'minimumIdle' is required; it must not be null");
        Assert.notNull(hikariProperties.getConnectionTimeout(), "Failed to create the datasource, this argument 'connectionTimeout' is required; it must not be null");

        HikariConfig hikariConfig = new HikariConfig();
        hikariConfig.setJdbcUrl(hikariProperties.getJdbcUrl());
        hikariConfig.setDriverClassName(hikariProperties.getDriverClassName());
        hikariConfig.setUsername(hikariProperties.getUsername());
        hikariConfig.setPassword(hikariProperties.getPassword());
        hikariConfig.setMaximumPoolSize(hikariProperties.getMaximumPoolSize());
        hikariConfig.setMinimumIdle(hikariProperties.getMinimumIdle());
        hikariConfig.setIdleTimeout(hikariProperties.getIdleTimeout());
        hikariConfig.setConnectionTimeout(hikariProperties.getConnectionTimeout());
        hikariConfig.setConnectionInitSql(hikariProperties.getConnectionInitSql());
        hikariConfig.setConnectionTestQuery(hikariProperties.getConnectionTestQuery());
        hikariConfig.setMaxLifetime(hikariProperties.getMaxLifetime());

        if (props != null) {
            props.forEach((key, value) -> {
                hikariConfig.addDataSourceProperty(String.valueOf(key), value);
            });
        }

        if (hikariProperties.getProps() != null) {
            hikariProperties.getProps().forEach((key, value) -> {
                hikariConfig.addDataSourceProperty(String.valueOf(key), value);
            });
        }

        HikariDataSourceBuilder builder = new HikariDataSourceBuilder(hikariConfig);
        return builder;
    }

    public HikariDataSourceBuilder wrapped() {
        this.wrapped = true;
        return this;
    }

    public DataSource build() {
        HikariDataSource dataSource = new HikariDataSource(hikariConfig);
        if (!wrapped) {
            return dataSource;
        }

        WrappedDataSource wds = new WrappedDataSource(dataSource);
        wds.setDriverClassName(hikariConfig.getDriverClassName());
        wds.setJdbcUrl(hikariConfig.getJdbcUrl());

        return wds;
    }

}
